package com.aloha.springframework.beans.factory;

import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.beans.PropertyValue;
import com.aloha.springframework.beans.PropertyValues;
import com.aloha.springframework.beans.factory.config.BeanDefinition;
import com.aloha.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.aloha.springframework.core.io.DefaultResourceLoader;
import com.aloha.springframework.core.io.Resource;
import com.aloha.springframework.utils.StringValueResolver;

import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;

/**
 * @author DaiZhiHeng
 * @description 用于解析占位符
 * @date 2023/7/7 14:13
 */
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {

    public static final String PLACEHOLDER_PREFIX = "${";

    public static final String PLACEHOLDER_SUFFIX = "}";

    private String location;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 加载属性配置文件
        Properties properties = loadProperties();

        // 属性值替换占位符
        processProperties(beanFactory, properties);

        // 往容器中添加字符解析器，供解析@Value注解使用
        StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
        beanFactory.addEmbeddedValueResolver(valueResolver);
    }

    /**
     * 加载配置文件
     */
    private Properties loadProperties() {
        try {
            DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
            Resource resource = resourceLoader.getResource(location);
            Properties properties = new Properties();
            properties.load(resource.getInputStream());
            return properties;
        } catch (IOException e) {
            throw new BeansException("无法加载配置文件 ", e);
        }
    }

    /**
     * 属性值替换占位符
     */
    private void processProperties(ConfigurableListableBeanFactory beanFactory, Properties properties) throws BeansException {
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            resolvePropertyValues(beanFactory.getBeanDefinition(beanName), properties);
        }
    }

    /**
     * 解析配置文件，并重新设置新的值
     */
    private void resolvePropertyValues(BeanDefinition beanDefinition, Properties properties) {
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue prop : propertyValues.getPropertyValues()) {
            Object value = prop.getValue();
            if (!(value instanceof String)) continue;
            String placeholder = resolvePlaceholder((String) value, properties);
            if (placeholder != null) {
                propertyValues.addPropertyValue(new PropertyValue(prop.getName(), placeholder));
            }
        }
    }

    public void setLocation(String location) {
        this.location = location;
    }

    private String resolvePlaceholder(String value, Properties properties) {
        if (!(value.startsWith(PLACEHOLDER_PREFIX) && value.endsWith(PLACEHOLDER_SUFFIX))) return value;
        String propKey = value.substring(2, value.length() - 1);
        return properties.getProperty(propKey);
    }

    private class PlaceholderResolvingStringValueResolver implements StringValueResolver {

        private final Properties properties;

        public PlaceholderResolvingStringValueResolver(Properties properties) {
            this.properties = properties;
        }

        @Override
        public String resolveStringValue(String strVal) throws BeansException {
            return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
        }
    }
}
